#ifndef __tenacitas_symbols_traverser_core_word_tester_h__
#define __tenacitas_symbols_traverser_core_word_tester_h__

#include <iostream>
#include <cstdint>
#include <string>

#include "runtest.h"

#include <tenacitas.symbols_traverser.core/word.h>
#include <tenacitas.translator.core/rc.h>

using namespace tenacitas::translator::core;

namespace tenacitas {
    namespace symbols_traverser {
        namespace core {

            class word_tester {

            private:
                struct supplier {
                    typedef std::string text;
                };

            private:

                static word<supplier> f() {
                    word<supplier> l_w("word 1", "a simple word",
                                        word<supplier>::easy);
                    return l_w;
                }
                

                template <typename t_word>
                static void print (const t_word & p_word){
                    std::cerr << "value = '" << p_word.get_value() << "'"
                              << std::endl;
                    std::cerr << "hint = '" << p_word.get_hint() << "'"
                              << std::endl;
                    std::cerr << "category = '" << p_word.get_category() << "'"
                              << std::endl;
                }
                    
                
                static bool test1() {
                    std::cerr << "\n+++ word_tester::test1" << std::endl;
                    typedef word<supplier> word;
                    
                    std::cerr << "very_easy = " << word::very_easy << std::endl;
                    std::cerr << "easy = " << word::easy << std::endl;
                    std::cerr << "medium = " << word::medium << std::endl;
                    std::cerr << "difficult = " << word::difficult << std::endl;
                    std::cerr << "very_difficult = " << word::very_difficult <<
                        std::endl; 
                    std::cerr << "impossible = " << word::impossible << std::endl;
                    return true;
                }

                static bool test2() {
                    std::cerr << "\n+++ word_tester::test2" << std::endl;
                    typedef word<supplier> word;

                    word l_word("word 1", "a simple word", word::easy);

                    return ( (l_word.get_value() == "word 1") &&
                             (l_word.get_hint() == "a simple word") &&
                             (l_word.get_category() == word::easy));
                }

                static bool test3() {
                    std::cerr << "\n+++ word_tester::test3" << std::endl;
                    typedef word<supplier> word;

                    word l_w1("word 1", "a simple word", word::easy); 
                    word l_w2("word 1", "a not so simple word", word::very_easy);

                    return (l_w1 == l_w2);
                }

                static bool test4() {
                    std::cerr << "\n+++ word_tester::test4" << std::endl;
                    typedef word<supplier> word;

                    word l_w1("word 1", "a simple word", word::easy);
                    word l_w2("word 2", "a simple word", word::easy);

                    return (l_w1 != l_w2);
                }

                static bool test5() {
                    std::cerr << "\n+++ word_tester::test5" << std::endl;
                    typedef word<supplier> word;

                    word l_w1("word 1", "a simple word", word::easy);
                    word l_w2(l_w1);

                    std::cerr << "w1: ";
                    print(l_w1);

                    std::cerr << "w2: ";
                    print(l_w2);
                    
                    
                    return (l_w1 == l_w2);
                }

                static bool test6() {
                    std::cerr << "\n+++ word_tester::test6" << std::endl;
                    typedef word<supplier> word;

                    word l_w1("word 1", "a simple word", word::easy);

                    std::cerr << "w1: ";
                    print(l_w1);

                    word l_w3(l_w1);

                    word l_w2(std::move(l_w1));

                    std::cerr << "w2: ";
                    print(l_w2);
                    
                    return (l_w2 == l_w3);
                }

                static bool test7() {
                    std::cerr << "\n+++ word_tester::test7" << std::endl;
                    typedef word<supplier> word;

                    word l_w1("word 1", "a simple word", word::easy);

                    word l_w2("word 2", "a simple word", word::easy);

                    return (l_w2 > l_w1);
                }

                static bool test8() {
                    std::cerr << "\n+++ word_tester::test8" << std::endl;
                    typedef word<supplier> word;

                    word l_w1("word 1", "a simple word", word::easy);

                    word l_w2("word 2", "a simple word", word::easy);

                    return (l_w2 >= l_w1);
                }

                static bool test9() {
                    std::cerr << "\n+++ word_tester::test9" << std::endl;
                    typedef word<supplier> word;

                    word l_w1("word 1", "a simple word", word::easy);

                    word l_w2("word 2", "a simple word", word::easy);

                    return (l_w1 < l_w2);
                }

                static bool test10() {
                    std::cerr << "\n+++ word_tester::test10" << std::endl;
                    typedef word<supplier> word;
                    
                    word l_w1("word 1", "a simple word", word::easy);

                    word l_w2("word 2", "a simple word", word::easy);

                    return (l_w1 <= l_w2);
                }

                static bool test11() {
                    std::cerr << "\n+++ word_tester::test11" << std::endl;
                    typedef word<supplier> word;

                    word l_w1("word 1", "a simple word", word::easy);

                    word l_w2(l_w1);

                    return (l_w2 <= l_w1);
                }

                static bool test12() {
                    std::cerr << "\n+++ word_tester::test12" << std::endl;
                    typedef word<supplier> word;

                    word l_w1("word 1", "a simple word", word::easy); 

                    word l_w2 = f();

                    return (l_w2 <= l_w1);
                }

                static bool test13() {
                    std::cerr << "\n+++ word_tester::test13" << std::endl;
                    typedef word<supplier> word;

                    try {
                        word l_w1("word 1", "a simple word", word::easy); 

                        std::cerr << l_w1 << std::endl;

                    }catch (rc_t & l_rc) {
                        std::cerr << "erro: " << l_rc.get_class_id()
                                  << ", " << l_rc.get_constant_id()
                                  << std::endl;
                        return false;
                    }
                    return true;
                    
                }

            

            public:
                static void run() {
                    runtest(word_tester::test1());
                    runtest(word_tester::test2());
                    runtest(word_tester::test3());
                    runtest(word_tester::test4());
                    runtest(word_tester::test5());
                    runtest(word_tester::test6());
                    runtest(word_tester::test7());
                    runtest(word_tester::test8());
                    runtest(word_tester::test9());
                    runtest(word_tester::test10());
                    runtest(word_tester::test11());
                    runtest(word_tester::test12());
                    runtest(word_tester::test13());
                }
            };
        }
    }
}

#endif
